<?php
declare (strict_types = 1);

/**
 * Here is your custom functions.
 */



// function isUndefined($var) {
//     return array_key_exists($var, get_defined_vars());
// }



//将 $input 数组的所有 $keys（逗号分隔） 的值取出
//$index为true，则用原 key 做关联，否则取出来为索引数组
//$default：如果 $input 中没有 某个key，则用这个默认值来替代（为null则跳过）
function array_keys_value(Array $input, $keys = null, $index = false, $default = null)
{
    $result = [];
    $keys = explode(',', $keys);
    
    foreach ($keys as $v) {
        if(array_key_exists($v, $input))
        {
            if($index)
                $result[$v] = $input[$v];
            else
                $result[] = $input[$v];
        }
        else if($default !== null)
        {
            if($index)
                $result[$v] = $default;
            else
                $result[] = $default;
        }

    }
    return $result;
}


/**
 * 返回数组（二维数组）中指定多列
 *
 * @param Array $input 需要取出数组列的多维数组
 * @param String $column_keys 要取出的列名，逗号分隔，如不传则返回所有列
 * @param String $index_key 作为返回数组的索引的列
 * @return Array
 */
function array_columns(Array $input, $column_keys = null, $index_key = null)
{
    $result = array();

    $keys = isset($column_keys) ? explode(',', $column_keys) : array();

    if ($input) {
        foreach ($input as $k => $v) {

            // 指定返回列
            if ($keys)
            {
                $tmp = array();
                foreach ($keys as $key)
                {
                    $tmp[$key] = $v[$key];
                }
            }
            else
            {
                $tmp = $v;
            }

            // 指定索引列
            if (isset($index_key))
            {
                $result[$v[$index_key]] = $tmp;
            }
            else
            {
                $result[] = $tmp;
            }
        }
    }

    return $result;
}






//鹰：获取客户真实IP
function get_real_ip(){
    $ip=FALSE;
    //客户端IP 或 NONE 
    if(!empty($_SERVER["HTTP_CLIENT_IP"]))
    {
        $ip = $_SERVER["HTTP_CLIENT_IP"];
    }
    //多重代理服务器下的客户端真实IP地址（可能伪造）,如果没有使用代理，此字段为空
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR']))
    {
        $ips = explode (", ", $_SERVER['HTTP_X_FORWARDED_FOR']);
        if ($ip) { array_unshift($ips, $ip); $ip = FALSE; }
        for ($i = 0; $i < count($ips); $i++) {
            if (!eregi ("^(10│172.16│192.168).", $ips[$i]))
            {
                $ip = $ips[$i];
                break;
            }
        }
    }
    //客户端IP 或 (最后一个)代理服务器 IP 
    return ($ip ? $ip : $_SERVER['REMOTE_ADDR']);
}

//get_client_ip(0)返回ip    get_client_ip(1)返回ipv4的数字地址
function get_client_ip($type = 0,$adv=false) {
    $type       =  $type ? 1 : 0;
    static $ip  =   NULL;
    if ($ip !== NULL)
    return $ip[$type];
    if($adv)
    {
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR']))
        {
            $arr    =   explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
            $pos    =   array_search('unknown',$arr);
            if(false !== $pos) unset($arr[$pos]);
            $ip     =   trim($arr[0]);
        }
        elseif (isset($_SERVER['HTTP_CLIENT_IP']))
        {
            $ip     =   $_SERVER['HTTP_CLIENT_IP'];
        }
        elseif (isset($_SERVER['REMOTE_ADDR']))
        {
            $ip     =   $_SERVER['REMOTE_ADDR'];
        }
    }
    elseif (isset($_SERVER['REMOTE_ADDR']))
    {
        $ip     =   $_SERVER['REMOTE_ADDR'];
    }
    // IP地址合法验证
    $long = sprintf("%u",ip2long($ip));
    $ip   = $long ? array($ip, $long) : array('0.0.0.0', 0);
    return $ip[$type];
}


//返回当前的毫秒时间戳
function msectime()
{
  list($msec, $sec) = explode(' ', microtime());
  $msectime =  (float)sprintf('%.0f', (floatval($msec) + floatval($sec)) * 1000);
  return $msectime;
}




//!!!修改自 我的 TP
//封装的通用返回json
use support\Response;
function ret_value($code=0, $msg="", $data=null, $httpCode=200, $header=[], $others=[])
{
    if(is_null($httpCode))
        $httpCode = 200;
    if(is_null($header))
        $header = [];

    $retData = array_merge($others, ["code" => $code, "msg" => $msg, "data" => $data]);
    
    $options = JSON_UNESCAPED_UNICODE;
    return new Response($httpCode, ['Content-Type' => 'application/json'], \json_encode($retData, $options));
    /*return json($retData)->
        code($httpCode)->
        header($header)
        //contentType()
    ;*/
}



//运行目录下所有php文件
//app_path(), \FilesystemIterator::FOLLOW_SYMLINKS
function include_path(string $path, int $flags = FilesystemIterator::KEY_AS_PATHNAME|FilesystemIterator::CURRENT_AS_FILEINFO)
{
    $dir_iterator = new \RecursiveDirectoryIterator($path, $flags);
    $iterator = new \RecursiveIteratorIterator($dir_iterator);
    foreach ($iterator as $file) {
        // 忽略目录和非php文件
        if (\is_dir($file->getPathname()) || $file->getExtension() != 'php') {
            continue;
        }
        /** var SplFileInfo $file */
        //if (\is_dir($file) || $file->getExtension() != 'php' || \in_array($file->getBaseName('.php'), $exclude_file)) {
        //    continue;
        //}
        
        include_once $file;
        //$config = include_once $file;
    }

}



//PHP版本的 .env文件：
//    env定义格式：return [ 'DB_HOST' => '这写数据库地址', 'DB_PASSWORD' => '这里写密码' ];
//注意：helpers.php 会在加载配置文件前加载，而 functions.php 在之后，所以需要用 envs 在配置文件中使用，则定义在 helpers.php 中；
//key为需返回的键，为null则返回整个配置数据；default为默认值；file为配置文件路径，每个配置文件数据都会被保存；
function _envs($key = null, $default = null, $file = null) {
    static $env_config = [];

    //默认配置文件路径
    if($file === null)
        $file = base_path(false) . '/envs.php';

    //读取配置文件，不存在则返回默认值
    if (!$env_config || !isset($env_config[$file])) {
        try {
            //$env_config[$file] = include $file;   //require；app.php 文件中使用envs方法，这两个会导致 app.php 无限载入（内存无限暴涨）
            $env_config[$file] = include_once $file;    //require_once
        }
        catch(\Exception $e) {
            return $default;
        }
    }

    //如果返回整个配置数据
    if($key === null)
        return $env_config[$file];
    else
        return $env_config[$file][$key] ?? $default;
}










//下面提取自 PearAdminTP5

// 应用公共文件
if (!function_exists('opt_photo'))
{
    //图库选择
    function opt_photo($val)
    {
       return '<button class="pear-btn pear-btn-primary pear-btn-sm" style="margin:4px 5px;vertical-align:top;" id="'.$val.'" type="button">图库选择</button>
       <script>
       layui.use(["jquery"],function() {
        let $ = layui.jquery;
        //弹出窗设置 自己设置弹出百分比
        function screen() {
            if (typeof width !== "number" || width === 0) {
            width = $(window).width() * 0.8;
            }
            if (typeof height !== "number" || height === 0) {
            height = $(window).height() - 20;
            }
            return [width + "px", height + "px"];
        }
        $("#'.$val.'").on("click", function () {
            layer.open({
                type: 2,
                maxmin: true,
                title: "图库选择",
                shade: 0.1,
                area: screen(),
                content:"../index/optPhoto",
                success:function (layero,index) {
                    var iframe = window["layui-layer-iframe" + index];
                    iframe.child("'.$val.'")
                }
            });
        });
        })
        </script>';
    }
}
if (!function_exists('rm'))
{
    //清除缓存
    function rm()
    {
        delete_dir(root_path().'runtime');
    }
}

if (!function_exists('is_url'))
{
    //是否
    function is_url($url)
    {
        if(preg_match("/^http(s)?:\\/\\/.+/",$url)) return $url;
    }
}

if (!function_exists('rand_string'))
{
    /**
     *  随机数
     *
     * @param string $length 长度
     * @param string $type   类型
     * @return void
     */
    function rand_string($length = '32',$type=4): string
    {
        $rand='';
        switch ($type) {
            case '1':
                $randstr= '0123456789';
                break;
            case '2':
                $randstr= 'abcdefghijklmnopqrstuvwxyz';
                break;
            case '3':
                $randstr= 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
                break;
            default:
                $randstr= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
                break;
        }
        $max = strlen($randstr)-1;
        mt_srand((double)microtime()*1000000);
        for($i=0;$i<$length;$i++) {
            $rand.=$randstr[mt_rand(0,$max)];
        }
        return $rand;
    }
}

if (!function_exists('set_password'))
{
    //密码截取
    function set_password($password): string
    {
      return substr(md5($password), 3, -3);
    }
}

/**
 * 数据签名认证
 */
function data_sign($data = [])
{
    if (!is_array($data)) {
        $data = (array)$data;
    }
    ksort($data);
    $code = http_build_query($data);
    $sign = sha1($code);
    return $sign;
}

/* *
 * 修改网站配置文件
 * /
if (!function_exists('set_web'))
{
    function set_web($data = [])
    {
        $str = "<?php\r\n/**\r\n * 系统配置文件\r\n * /\r\nreturn [\r\n";
        foreach ($data as $key => $value) {
            if(is_array($value)){
            $str .= getArrTree($key,$value);
            }else{
                $str .= "\t'$key' => '$value',";
                $str .= "\r\n";
            }
        }
        $str .= '];';
        @file_put_contents(config_path().'web.php', $str);
    }
}
*/

if (!function_exists('get_arr_tree'))
{
    /**
     * 递归配置数组
     */
    function get_arr_tree($key,$data,$level="\t")
    {
        $i = "$level'$key' => [\r\n";
        foreach ($data as $k => $v) {
            if(is_array($v))
            {
                $i .= get_arr_tree($k,$v,$level."\t");
            }
            else
            {
                $i .= "$level\t'$k' => '$v',";
                $i .= "\r\n";      
            }
        }
        return  $i."$level".'],'."\r\n";
    }
}

if (!function_exists('aes_encrypt'))
{
    /**
     *
     * @param string $string 需要加密的字符串
     * @param string $key 密钥
     * @return string
     */
    function aes_encrypt($string, $key="ONSPEED"): string
    {
        $data = openssl_encrypt($string, 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
        return strtolower(bin2hex($data));
    }
}

if (!function_exists('aes_decrypt'))
{
    /**
     * @param string $string 需要解密的字符串
     * @param string $key 密钥
     * @return string
     */
    function aes_decrypt($string, $key="ONSPEED"): string
    {
        try {
            return openssl_decrypt(hex2bin($string), 'AES-128-ECB', $key, OPENSSL_RAW_DATA);
        }catch (\Exception $e){
            return false;
        }
    }
}

if (!function_exists('get_field'))
{
    /**
     * 获取指定表指定行指定字段
     * @param  string       $tn      完整表名
     * @param  string|array $where   参数数组或者id值
     * @param  string       $field   字段名,默认'name'
     * @param  string       $default 获取失败的默认值,默认''
     * @param  array        $order   排序数组
     * @return string                获取到的内容
     */
    function get_field($tn, $where, $field = 'name', $default = '', $order = ['id' => 'desc'])
    {
        if (!is_array($where))
        {
            $where = ['id' => $where];
        }
        $row = \think\facade\Db::name($tn)->field([$field])->where($where)->order($order)->find();
        return $row === null ? $default : $row[$field];
    }
  }

  if (!function_exists('delete_dir'))
  {
    /**
     * 遍历删除文件夹所有内容
     * @param  string $dir 要删除的文件夹
     */
    function delete_dir($dir)
    {
        $dh = opendir($dir);
        while ($file = readdir($dh))
        {
            if ($file != '.' && $file != '..')
            {
                $filepath = $dir . '/' . $file;
                if (is_dir($filepath))
                {
                    delete_dir($filepath);
                }
                else
                {
                    @unlink($filepath);
                }
            }
        }
        closedir($dh);
        @rmdir($dir);
    }
  }

  if (!function_exists('get_tree'))
  {
    /**
     * 递归无限级分类权限
     * @param array $data
     * @param int $pid
     * @param string $field1 父级字段
     * @param string $field2 子级关联的父级字段
     * @param string $field3 子级键值
     * @return mixed
     */
    function get_tree($data, $pid = 0, $field1 = 'id', $field2 = 'pid', $field3 = 'children')
    {
        $arr = [];
        foreach ($data as $k => $v)
        {
            if ($v[$field2] == $pid)
            {
                $v[$field3] = get_tree($data, $v[$field1]);
                $arr[] = $v;
            }
        }
        return $arr;
    }
  }

  if (!function_exists('hump_underline'))
  {
    /**
     * 驼峰转下划线
     * @param  string $str 需要转换的字符串
     * @return string      转换完毕的字符串
     */
    function hump_underline($str)
    {
        return strtolower(trim(preg_replace('/[A-Z]/', '_\\0', $str), '_'));
    }
 }

  if (!function_exists('underline_hump'))
  {
    /**
     * 下划线转驼峰
     * @param  string $str 需要转换的字符串
     * @return string      转换完毕的字符串
     */
    function underline_hump($str)
    {
        return ucfirst(
            preg_replace_callback('/_([a-zA-Z])/', function ($match) {
                return strtoupper($match[1]);
            }, $str)
        );
    }
  }

  if (!function_exists('record_log'))
  {
    /**
     * @记录日志
     * @param [type] $param
     * @param string $file
     *
     * @return void
     */
     function record_log($param,$file='')
     {
        $path = root_path().'log/'.$file."/";
        if (!is_dir($path)) @mkdir($path,0777,true);
        if (is_array($param)){
            $param = json_encode($param,JSON_FORCE_OBJECT|JSON_UNESCAPED_UNICODE);
        }
        @file_put_contents(
            $path.date("Y_m_d",time()).".txt",
            "执行日期："."\r\n".date('Y-m-d H:i:s', time()) . ' ' . "\n" . $param . "\r\n",
            FILE_APPEND
        );
    }

}
